<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="fTxQ3" id="fTxQ3"><span data-lake-id="u02915f01" id="u02915f01">典型回答</span></h1>
  <p data-lake-id="u78dccbfe" id="u78dccbfe"><br></p>
  <p data-lake-id="u1d5078cc" id="u1d5078cc"><br></p>
  <p data-lake-id="u06afe48f" id="u06afe48f"><span data-lake-id="u7c658c4d" id="u7c658c4d">ThreadLocal 提供了一种线程级别的数据存储机制。每个线程都拥有自己独立的 ThreadLocal 副本，这意味着每个线程都可以独立地、安全地操作这些变量，而不会影响其他线程。</span></p>
  <p data-lake-id="u83148d17" id="u83148d17"><span data-lake-id="u7aa5fc0a" id="u7aa5fc0a">​</span><br></p>
  <p data-lake-id="uaa122dc5" id="uaa122dc5"><span data-lake-id="u7b16c3a8" id="u7b16c3a8">ThreadLocal其实在工作中应该是非常常见的，以下是一些比较典型的使用场景：</span></p>
  <p data-lake-id="ucf120e4b" id="ucf120e4b"><span data-lake-id="u24ab3e6a" id="u24ab3e6a">​</span><br></p>
  <p data-lake-id="ue43630c6" id="ue43630c6"><strong><span data-lake-id="u50aeac31" id="u50aeac31">用户身份信息存储</span></strong><span data-lake-id="u83d5a2bc" id="u83d5a2bc">： 在很多应用中，都需要做登录鉴权，一旦鉴权通过之后，就可以把用户信息存储在ThreadLocal中，这样在后续的所有流程中，需要获取用户信息的，直接取ThreadLocal中获取就行了。非常的方便。</span></p>
  <p data-lake-id="u9f7b3cba" id="u9f7b3cba"><br></p>
  <p data-lake-id="uec265e1c" id="uec265e1c"><strong><span data-lake-id="ue483ef6f" id="ue483ef6f">线程安全</span></strong><span data-lake-id="u73ccb730" id="u73ccb730">：ThreadLocal可以用来定义一些需要并发安全处理的成员变量，比如SimpleDateFormat，由于 SimpleDateFormat 不是线程安全的，可以使用 ThreadLocal 为每个线程创建一个独立的 SimpleDateFormat 实例，从而避免线程安全问题。</span></p>
  <p data-lake-id="ud13edc89" id="ud13edc89"><span data-lake-id="u0c7dc973" id="u0c7dc973">​</span><br></p>
  <p data-lake-id="uf0d1e0fd" id="uf0d1e0fd"><strong><span data-lake-id="u0d4a30f3" id="u0d4a30f3">日志上下文存储</span></strong><span data-lake-id="u1c5e6b3c" id="u1c5e6b3c">：在Log4j等日志框架中，经常使用ThreadLocal来存储与当前线程相关的日志上下文。这允许开发者在日志消息中包含特定于线程的信息，如用户ID或事务ID，这对于调试和监控是非常有用的。</span></p>
  <p data-lake-id="u881ef337" id="u881ef337"><br></p>
  <p data-lake-id="ucdd96f62" id="ucdd96f62"><strong><span data-lake-id="ucc71139f" id="ucc71139f">traceId存储：</span></strong><span data-lake-id="u8e2f160c" id="u8e2f160c">和上面存储日志上下文类似，在分布式链路追中中，需要存储本次请求的traceId，通常也都是基于ThreadLocal存储的。</span></p>
  <p data-lake-id="u91136147" id="u91136147"><span data-lake-id="u65688c82" id="u65688c82">​</span><br></p>
  <p data-lake-id="ud8a9e3d4" id="ud8a9e3d4"><strong><span data-lake-id="ud6d336c9" id="ud6d336c9">数据库Session：</span></strong><span data-lake-id="ud4ee0cef" id="ud4ee0cef">很多ORM框架，如Hibernate、Mybatis，都是使用ThreadLocal来存储和管理数据库会话的。这样可以确保每个线程都有自己的会话实例，避免了在多线程环境中出现的线程安全问题。</span></p>
  <p data-lake-id="u27152639" id="u27152639"><span data-lake-id="ud2f9f645" id="ud2f9f645">​</span><br></p>
  <p data-lake-id="u1b7a5dd8" id="u1b7a5dd8"><strong><span data-lake-id="u51682897" id="u51682897">PageHelper分页</span></strong><span data-lake-id="u7602d56b" id="u7602d56b">：PageHelper是MyBatis中提供的分页插件，主要是用来做物理分页的。我们在代码中设置的分页参数信息，页码和页大小等信息都会存储在ThreadLocal中，方便在执行分页时读取这些数据。</span></p>
  <p data-lake-id="u75b02929" id="u75b02929"><br></p>
  <p data-lake-id="uca601042" id="uca601042"><br></p>
  <p data-lake-id="u686fa5e8" id="u686fa5e8"><span data-lake-id="u0d5425f0" id="u0d5425f0">其实，看了这么多，主要就是俩作用：</span></p>
  <p data-lake-id="u9c237fa1" id="u9c237fa1"><span data-lake-id="u3c8faef4" id="u3c8faef4">​</span><br></p>
  <p data-lake-id="u3afb6756" id="u3afb6756"><strong><span data-lake-id="u1cb5e142" id="u1cb5e142">1、解决并发问题</span></strong><span data-lake-id="ubd902f3c" id="ubd902f3c">，这个不需要多说了。</span></p>
  <p data-lake-id="u99f24f8c" id="u99f24f8c"><strong><span data-lake-id="u1de091f2" id="u1de091f2">2、在线程中传递数据</span></strong><span data-lake-id="u9302d47c" id="u9302d47c">，在同一个线程执行过程中，ThreadLocal的数据一直在，所以我们可以在前面把数据放到ThreadLocal中，然后再后面的时候再取出来用，就可以避免要把这些数据一直通过参数传递。</span></p>
 </body>
</html>